package com.ouyunc.file.plugins.local;

import com.ouyunc.common.constant.CommonConstant;
import com.ouyunc.common.constant.enums.FilePluginEnum;
import com.ouyunc.common.context.SpringContextHolder;
import com.ouyunc.common.utils.SnowflakeUtil;
import com.ouyunc.file.plugins.AbstractUploaderDownloader;
import com.ouyunc.file.plugins.base.UploadConfig;
import com.ouyunc.file.plugins.base.FileReturn;
import com.ouyunc.file.plugins.base.DownloadConfig;
import com.ouyunc.file.plugins.properties.FileProperties;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 * @Author fangzhenxun
 * @Description 本地文件上传
 * @Date 2020/11/30 16:07
 **/
public class LocalFilePlugin extends AbstractUploaderDownloader {

    private static final Logger log = LoggerFactory.getLogger(LocalFilePlugin.class);

    private static final FileProperties fileProperties;

    static {
        // 读取配置文件中的数据
        fileProperties = SpringContextHolder.getBean(FileProperties.class);
    }


    @Override
    public FilePluginEnum pluginEnum() {
        return FilePluginEnum.LOCAL;
    }



    @Override
    public void download(String fileUri, String fileName, DownloadConfig config) {
        long beginTime = System.currentTimeMillis();
        //从数据库查询该文件原始名称
        //获取当前response 对象
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletResponse response = servletRequestAttributes.getResponse();

        try(WritableByteChannel writableByteChannel = Channels.newChannel(response.getOutputStream())) {
            if (StringUtils.isNotEmpty(fileName)) {
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, CommonConstant.UTF_8));
                if (config != null) {
                    // mime 类型
                    if (StringUtils.isNoneBlank(config.getContentType())) {
                        response.setContentType(config.getContentType());
                    }
                    // 请求头
                    if (MapUtils.isNotEmpty(config.getHeaderMap())) {
                        config.getHeaderMap().forEach((key, value)->{
                            response.setHeader(key, value);
                        });
                    }
                }
            }
            URL url = new URL(fileUri);
            ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream());
            ByteBuffer buffer= ByteBuffer.allocate(10*1024);
            while(readableByteChannel.read(buffer)!=-1){
                buffer.flip();
                while(buffer.hasRemaining()){
                    writableByteChannel.write(buffer);
                }
                buffer.clear();
            }
        }catch (IOException e) {
            log.error("文件下载失败！");
            e.printStackTrace();
        }
        log.info("下载 cost time: {} ms" , (System.currentTimeMillis() - beginTime));
    }

    /**
     * @Author fangzhenxun
     * @Description
     * @param bytes
     * @param fileName
     * @return void
     */
    @Override
    public void download(byte[] bytes, String fileName, DownloadConfig config) {
        long beginTime = System.currentTimeMillis();
        //从数据库查询该文件原始名称
        //获取当前response 对象
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        try(WritableByteChannel writableByteChannel = Channels.newChannel(response.getOutputStream())) {
            if (StringUtils.isNotEmpty(fileName)) {
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, CommonConstant.UTF_8));
                if (config != null) {
                    // mime 类型
                    if (StringUtils.isNoneBlank(config.getContentType())) {
                        response.setContentType(config.getContentType());
                    }
                    // 请求头
                    if (MapUtils.isNotEmpty(config.getHeaderMap())) {
                        config.getHeaderMap().forEach((key, value)->{
                            response.setHeader(key, value);
                        });
                    }
                }
            }
            ByteBuffer buffer = ByteBuffer.wrap(bytes);
            writableByteChannel.write(buffer);
            buffer.clear();
        }catch (IOException e) {
            log.error("文件下载失败！");
            e.printStackTrace();
        }
        log.info("下载 cost time: {} ms" , (System.currentTimeMillis() - beginTime));
    }


    @Override
    public FileReturn upload(MultipartFile file, UploadConfig configItem) {
        //@todo 可以通过构建者来构建
        long beginTime = System.currentTimeMillis();
        String originalFilename = file.getOriginalFilename();
        int index = originalFilename.lastIndexOf('.');
        String fileSuffix = originalFilename.substring(index);
        String newFileName = SnowflakeUtil.nextId() + "_" + originalFilename;
        String filePath = fileProperties.getLocal().getUploadPath() + newFileName;
        long fileSize = file.getSize();
        // 这里下载前缀地址先写死，后期通过配置文件来配置
        String fileUrl = null;

        //使用nio零拷贝
        try (FileChannel outChannel = FileChannel.open(Paths.get(filePath), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
             FileInputStream fileInputStream = (FileInputStream) file.getInputStream();
             FileChannel inChannel = fileInputStream.getChannel()) {
            outChannel.transferFrom(inChannel, 0, inChannel.size());
            fileUrl = fileProperties.getLocal().getEndpoint() + URLEncoder.encode(newFileName, CommonConstant.UTF_8);
        }catch (Exception e) {
            log.error("文件上传到本地失败！");
            e.printStackTrace();
            throw new RuntimeException("文件上传到本地失败！");
        }
        log.info("上传 cost time: {} ms" , (System.currentTimeMillis() - beginTime));
        return new FileReturn(originalFilename, newFileName, fileSuffix, fileUrl ,fileSize);
    }


    @Override
    public FileReturn copy(String srcFilePath, UploadConfig configItem) {
        return null;
    }
}
